import React, { useEffect, useState, useRef } from 'react';
import { fabric } from 'fabric';
import { useDispatch, useSelector } from 'react-redux';
import { sendCustomeizeMessage } from '@/utils/lib';
import { setScreenStream } from '@/store/reducers/stream';

interface CanvasProps {
	width?: number;
	height?: number;
	tool?: any;
	clientId?: string;
}

enum DrawStatus {
	START = 'start',
	END = 'end'
}

enum DrawMode {
	ARROW = 'arrow',
	LINE = 'line',
	CIRCLE = 'circle',
	SQUARE = 'square',
	TEXT = 'text',
	DOTTEDLINE = 'dottedline',
	ELLIPSE = 'ellipse',
	REACTANGLE = 'rectangle',
	REMOVE = 'remove'
}

let canvasContainer: fabric.Canvas | null = null;
let drawingObject: any = null;
let isDrawing = false;
let moveCount = 1;
let drawTool = '';
let drawText: fabric.Textbox | null = null;
let cacheDrawData: string = '';

const Canvas = (props: CanvasProps) => {
	const dispatch = useDispatch();
	const { clientId } = props;
	const [zoom, setZoom] = useState<number>(1);
	const mouseFrom = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
	const mouseTo = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
	const [color, setColor] = useState('#E34F51');
	const [drawWidth, setDrawWidth] = useState<number>(4);
	const screenStreams = useSelector((state: any) => state.screenStreams);

	useEffect(() => {
		console.log('initCanvas');
		drawTool = 'pen';
		dispatch(setScreenStream({ tool: { desc: '', icon: 'icon-widget-qianbi', id: 1, mode: 'pen' } }));
		initCanvas();
	}, []);

	const initCanvas = () => {
		canvasContainer = new fabric.Canvas('widget-white-board-canvas', {
			containerClass: 'widget-canvas-contaier'
		});
		const context = canvasContainer?.getContext()!;
		context.globalAlpha = 1;
		context.fillStyle = 'rgba(255, 255, 255, 0)';
		canvasContainer.isDrawingMode = false;
		canvasContainer.freeDrawingBrush.color = color;
		fabric.util.addClass(document.querySelector('.widget-canvas-contaier')!.childNodes[1] as HTMLCanvasElement, 'widget-upper-canvas');
		mouseUp();
		mouseDown();
		mouseMove();
		selection();
		objectMove();
	};

	const mouseUp = () => {
		canvasContainer?.on('mouse:up', options => {
			const offsetX = navigator.userAgent.match(/android/i) || navigator.userAgent.match(/(iPhone|iPod|iPad);?/i) ? options.pointer!.x : options.e.offsetX;
			const offsetY = navigator.userAgent.match(/android/i) || navigator.userAgent.match(/(iPhone|iPod|iPad);?/i) ? options.pointer!.y : options.e.offsetY;
			const xy = transformMouse(offsetX, offsetY);
			mouseTo.current = { x: xy.x, y: xy.y };
			moveCount = 1;
			drawingObject = null;
			isDrawing = false;
			updateCanvas();
		});
	};

	const mouseMove = () => {
		canvasContainer?.on('mouse:move', options => {
			if (moveCount % 2 && !isDrawing) {
				//减少绘制频率
				return;
			}
			moveCount++;
			const offsetX = navigator.userAgent.match(/android/i) || navigator.userAgent.match(/(iPhone|iPod|iPad);?/i) ? options.pointer!.x : options.e.offsetX;
			const offsetY = navigator.userAgent.match(/android/i) || navigator.userAgent.match(/(iPhone|iPod|iPad);?/i) ? options.pointer!.y : options.e.offsetY;
			const xy = transformMouse(offsetX, offsetY);
			mouseTo.current = { x: xy.x, y: xy.y };
			drawing();
		});
	};

	const mouseDown = () => {
		canvasContainer?.on('mouse:down', options => {
			const offsetX = navigator.userAgent.match(/android/i) || navigator.userAgent.match(/(iPhone|iPod|iPad);?/i) ? options.pointer!.x : options.e.offsetX;
			const offsetY = navigator.userAgent.match(/android/i) || navigator.userAgent.match(/(iPhone|iPod|iPad);?/i) ? options.pointer!.y : options.e.offsetY;
			const xy = transformMouse(offsetX, offsetY);
			mouseFrom.current = { x: xy.x, y: xy.y };
			if (drawTool === 'text') {
				drawing();
			} else {
				isDrawing = true;
			}
		});
	};

	const selection = () => {
		canvasContainer?.on('selection:created', (e: fabric.IEvent<Event>) => {
			if (drawText) {
			} else {
				if (e.selected && e.selected.length > 0) {
					//多选删除
					const etCount = e.selected.length;
					for (var etindex = 0; etindex < etCount; etindex++) {
						canvasContainer?.remove(e.selected[etindex]);
					}
				} else {
					//单选删除
					canvasContainer?.remove(e.selected as any);
				}
			}

			canvasContainer?.discardActiveObject(); //清楚选中框
			updateCanvas();
		});
	};

	const objectMove = () => {
		canvasContainer?.on('object:moving', options => {
			console.log(options);
		});
	};

	useEffect(() => {
		if (canvasContainer) {
			canvasContainer.isDrawingMode = false;
			if (drawText) {
				//退出文本编辑状态
				drawText.exitEditing();
				drawText = null;
				updateCanvas();
			}
			if (screenStreams.tool && screenStreams.tool.mode) {
				drawTool = screenStreams.tool.mode || 'pen';
				switch (drawTool) {
					case 'pen':
						canvasContainer.isDrawingMode = true;
						break;
					case 'remove':
						canvasContainer.selection = true;
						canvasContainer.skipTargetFind = false;
						break;
					case 'text':
						canvasContainer.skipTargetFind = true; //画板元素不能被选中
						canvasContainer.selection = false; //画板不显示选中
						break;

					default: //画板元素不能被选中
						//画板不显示选中
						canvasContainer.skipTargetFind = true;
						canvasContainer.selection = false;
						break;
				}
			}
		}
	}, [screenStreams]);

	useEffect(() => {
		return () => {
			canvasContainer?.dispose();
			console.log('screen mark dispose success');
		};
	}, []);

	const transformMouse = (mouseX: number, mouseY: number) => {
		return { x: mouseX / zoom, y: mouseY / zoom };
	};

	const updateCanvas = () => {
		const canvasStringify = JSON.stringify(canvasContainer);
		cacheDrawData = canvasStringify;
		console.log(cacheDrawData);
		sendDrawData();
	};
	const clearCanvas = () => {
		canvasContainer?.clear();
	};

	const sendDrawData = async () => {
		try {
			let data = {
				businessType: 'mark_trace',
				message: {
					track: cacheDrawData
				}
			};
			const resp = await sendCustomeizeMessage(data, clientId!);
			console.log('update canvas track success', resp);
		} catch (error) {
			console.log('update canvas track error', error);
		}
	};

	const drawing = () => {
		if (drawingObject) {
			canvasContainer?.remove(drawingObject);
		}
		if (canvasContainer) {
			canvasContainer.selection = false;
			canvasContainer.skipTargetFind = true;
		}
		let canvasObject = null;

		switch (drawTool) {
			case 'arrow': //箭头
				canvasObject = new fabric.Path(drawArrow(mouseFrom.current.x, mouseFrom.current.y, mouseTo.current.x, mouseTo.current.y, 30, 30), {
					stroke: color,
					fill: 'rgba(255,255,255,0)',
					strokeWidth: drawWidth
				});
				break;
			case 'line': //直线
				canvasObject = new fabric.Line([mouseFrom.current.x, mouseFrom.current.y, mouseTo.current.x, mouseTo.current.y], {
					stroke: color,
					strokeWidth: drawWidth
				});
				break;
			case 'dottedline': //虚线
				canvasObject = new fabric.Line([mouseFrom.current.x, mouseFrom.current.y, mouseTo.current.x, mouseTo.current.y], {
					strokeDashArray: [3, 1],
					stroke: color,
					strokeWidth: drawWidth
				});
				break;
			case 'circle': {
				//正圆
				let left = mouseFrom.current.x;
				let top = mouseFrom.current.y;
				let radius = Math.sqrt((mouseTo.current.x - left) * (mouseTo.current.x - left) + (mouseTo.current.y - top) * (mouseTo.current.y - top)) / 2;
				canvasObject = new fabric.Circle({
					left: left,
					top: top,
					stroke: color,
					fill: 'rgba(255, 255, 255, 0)',
					radius: radius,
					strokeWidth: drawWidth
				});

				break;
			}
			case 'ellipse': {
				//椭圆
				let left = mouseFrom.current.x;
				let top = mouseFrom.current.y;
				canvasObject = new fabric.Ellipse({
					left: left,
					top: top,
					stroke: color,
					fill: 'rgba(255, 255, 255, 0)',
					originX: 'center',
					originY: 'center',
					rx: Math.abs(left - mouseTo.current.x),
					ry: Math.abs(top - mouseTo.current.y),
					strokeWidth: drawWidth
				});
				break;
			}
			case 'square':
				canvasObject = canvasObject = new fabric.Rect({
					left: mouseFrom.current.x,
					top: mouseFrom.current.y,
					width: mouseTo.current.x - mouseFrom.current.x,
					height: mouseTo.current.y - mouseFrom.current.y,
					fill: 'rgba(255, 255, 255, 0)',
					stroke: color,
					strokeWidth: drawWidth
				});
				break;
			case 'text':
				drawText = new fabric.Textbox('', {
					left: mouseFrom.current.x,
					top: mouseFrom.current.y,
					width: 300,
					lineHeight: 1.1,
					moveCursor: 'pointer',
					fontSize: 18,
					fill: color,
					hasControls: false
				});
				canvasContainer?.add(drawText);
				canvasContainer?.setActiveObject(drawText);
				drawText.enterEditing();
				drawText.hiddenTextarea!.focus();
				break;
			case 'remove':
				if (canvasContainer) {
					canvasContainer.selection = true;
					canvasContainer.skipTargetFind = false;
				}

				break;
			default:
				break;
		}
		if (canvasObject) {
			console.log(canvasObject);
			canvasContainer?.add(canvasObject);
			drawingObject = canvasObject;
		}
	};

	const drawArrow = (fromX: number, fromY: number, toX: number, toY: number, theta: number, headlen: number) => {
		// 绘制箭头
		theta = typeof theta != 'undefined' ? theta : 30;
		headlen = typeof theta != 'undefined' ? headlen : 10;
		// 计算各角度和对应的P2,P3坐标
		const angle = (Math.atan2(fromY - toY, fromX - toX) * 180) / Math.PI,
			angle1 = ((angle + theta) * Math.PI) / 180,
			angle2 = ((angle - theta) * Math.PI) / 180,
			topX = headlen * Math.cos(angle1),
			topY = headlen * Math.sin(angle1),
			botX = headlen * Math.cos(angle2),
			botY = headlen * Math.sin(angle2);
		let arrowX = fromX - topX,
			arrowY = fromY - topY;
		let path = ' M ' + fromX + ' ' + fromY;
		path += ' L ' + toX + ' ' + toY;
		arrowX = toX + topX;
		arrowY = toY + topY;
		path += ' M ' + arrowX + ' ' + arrowY;
		path += ' L ' + toX + ' ' + toY;
		arrowX = toX + botX;
		arrowY = toY + botY;
		path += ' L ' + arrowX + ' ' + arrowY;
		return path;
	};

	const { width = 375, height = 600 } = props;
	return (
		<div className="widget-white-board">
			<canvas id="widget-white-board-canvas" width={width} height={height}></canvas>
		</div>
	);
};

export default Canvas;
